#include "HKSDK_2023.h"
#include <iostream>
#include <conio.h>
#include <process.h>
#include <opencv2/imgproc/types_c.h>
#include "logger.h"
#include <QSettings>
#include "HCNetSDK.h"
#include "PlayM4.h"	//PlayM4

using namespace std;
static void CALLBACK HCSdkRealImage(LONG, DWORD, BYTE *, DWORD, void *);
static void CALLBACK HCSdkDecCallBackMend(long, char *, long, FRAME_INFO *, long, long);

typedef struct cam_img_info
{
	cv::Mat last_img;
	std::mutex last_img_mtx;
	long nPort;
	int frame_num;
}CAM_IMG_INFO;

static CAM_IMG_INFO gCam_img_info[2];

HKSDK_2023::HKSDK_2023()
{

}

int HKSDK_2023::init()
{
    char file_ini[64] = CONFIG_FILE_PATH;
	char cam0_part_name[64] = "camera0";
	char cam1_part_name[64] = "camera1";
	camera[0].num = 0;
	//camera[0].deviceIP = std::string("192.168.4.64");
	//camera[0].devicePort = 8000;
	read_ip_port_ini(file_ini, cam0_part_name, camera[0].deviceIP, (int&)camera[0].devicePort);
	camera[0].deviceUser = std::string("admin");
	camera[0].devicePasswords = std::string("fr888888");
	LOG(INFO)  << "camera[0].devicePort = " << camera[0].devicePort << "; camera[0].deviceIP = " << camera[0].deviceIP << endl;

	camera[1].num = 1;
//	camera[1].deviceIP = std::string("192.168.4.65");
//	camera[1].devicePort = 8000;
	read_ip_port_ini(file_ini, cam1_part_name, camera[1].deviceIP, (int&)camera[1].devicePort);
	camera[1].deviceUser = std::string("admin");
	camera[1].devicePasswords = std::string("fr888888");
	LOG(INFO) << "camera[1].devicePort = " << camera[1].devicePort << "; camera[1].deviceIP = " << camera[1].deviceIP << endl;

	testThread[0] = std::thread(&HKSDK_2023::test_thread_fun, this, 0);
	testThread[1] = std::thread(&HKSDK_2023::test_thread_fun, this, 1);
	return 0;
}

void HKSDK_2023::get_last_img(cv::Mat& img, int num)
{
	gCam_img_info[num].last_img_mtx.lock();
	gCam_img_info[num].last_img.copyTo(img);
	gCam_img_info[num].last_img_mtx.unlock();
}

void HKSDK_2023::test_thread_fun(int cam_num)
{
	LOG(INFO) << "test_thread_fun GetCurrentThreadId" << GetCurrentThreadId()<< std::endl;
	
	// 初始化SDK
	bool rFlag = NET_DVR_Init();
	if (!rFlag)
	{
		LOG(ERROR) << "NET_DVR_Init error! rFlag " << rFlag <<std::endl;
		return;
	}

	CAM_USING_INFO& camera = this->camera[cam_num];
	// 配置登陆SDK信息
	NET_DVR_USER_LOGIN_INFO  struLoginInfo;
	memset(&struLoginInfo, 0, sizeof(NET_DVR_USER_LOGIN_INFO));
	strcpy_s((char *)struLoginInfo.sDeviceAddress, sizeof(struLoginInfo.sDeviceAddress), camera.deviceIP.c_str());
	strcpy_s((char *)struLoginInfo.sUserName, sizeof(struLoginInfo.sUserName), camera.deviceUser.c_str());
	strcpy_s((char *)struLoginInfo.sPassword, sizeof(struLoginInfo.sPassword), camera.devicePasswords.c_str());
	struLoginInfo.wPort = camera.devicePort;
	struLoginInfo.bUseAsynLogin = 0;

	// 获取设备信息结构体
	NET_DVR_DEVICEINFO_V40 struDeviceInfo;
	memset(&struDeviceInfo, 0, sizeof(NET_DVR_DEVICEINFO_V40));

	// 登陆并获取设备信息
	int mUserID = NET_DVR_Login_V40(&struLoginInfo, &struDeviceInfo);
	if (mUserID == -1)
	{
		LOG(ERROR) << "NET_DVR_Login_V40 error! Err num =" << NET_DVR_GetLastError() << std::endl;
		return;
	}

	// 准备播放
	NET_DVR_PREVIEWINFO struPlayInfo;
	struPlayInfo.hPlayWnd = nullptr;        // 需要SDK解码时句柄设为有效值,仅取流不指定显示时设为空
	struPlayInfo.lChannel = 1;              // 预览通道号
	struPlayInfo.dwStreamType = 0;          // 0-主码流、1-子码流、2-码流3、3-码流4，以此类推
	struPlayInfo.dwLinkMode = 0;            // 0-TCP、1-UDP、2-多播、3-RTP、4、RTP/RTSP、5-RTSP/HTTP
	struPlayInfo.bBlocked = 0;
	struPlayInfo.byPreviewMode = 0;
	struPlayInfo.dwDisplayBufNum = 1;

	// 开始播放
	camera.lRealPlayHandle = NET_DVR_RealPlay_V40(mUserID, &struPlayInfo, HCSdkRealImage, &camera);
	if (camera.lRealPlayHandle == -1)
	{
		// DWORD err = NET_DVR_GetLastError();
		LOG(ERROR) << "NET_DVR_RealPlay_V40 error!" << std::endl;
		return;
	}
}

void HCSdkRealImage(LONG lPlayHandle, DWORD dwDataType, BYTE *pBuffer, DWORD dwBufSize, void *pUser)
{
    (LONG)lPlayHandle;
	CAM_USING_INFO *This = (CAM_USING_INFO *)pUser;
	//std::cout << "HCSdkRealImage !" << std::endl;
	if (This)
    {
        //DWORD dRet;
		switch (dwDataType)
		{
		case NET_DVR_SYSHEAD:                            // 系统头
			if (!PlayM4_GetPort(&(This->devicePort)))    // 获取播放库未使用的通道号
			{
				break;
			}
			if (dwBufSize > 0)
			{
				if (!PlayM4_SetStreamOpenMode(This->devicePort, STREAME_REALTIME))         // 设置实时流播放模式
				{
					break;
				}
				if (!PlayM4_OpenStream(This->devicePort, pBuffer, dwBufSize, 1024 * 1024))    // 打开流接口
				{
					break;
				}
				if (PlayM4_SetDecCallBackMend(This->devicePort, HCSdkDecCallBackMend,0))
				{

				}
				if (!PlayM4_Play(This->devicePort, nullptr))  // 播放开始
				{
					break;
				}
			}

			gCam_img_info[This->num].nPort = This->devicePort;
			break;
		case NET_DVR_STREAMDATA:        // 码流数据
			if (dwBufSize > 0 && This->devicePort != -1)
			{
				if (!PlayM4_InputData(This->devicePort, pBuffer, dwBufSize))
				{

				}
			}
			break;
		default:                        // 其他数据
			if (dwBufSize > 0 && This->devicePort != -1)
			{
				if (!PlayM4_InputData(This->devicePort, pBuffer, dwBufSize))
				{

				}
			}
			break;
		}
	}
	This = nullptr;
}

void HCSdkDecCallBackMend(long nPort, char *pBuf, long nSize, FRAME_INFO *pFrameInfo, long nUser, long Resever)
{
    (long)Resever;
    (long)nUser;
    (long)nSize;

	int num = -1;
	if (gCam_img_info[0].nPort == nPort) {
		num = 0;
	}
	else if (gCam_img_info[1].nPort == nPort) {
		num = 1;
	}

	if (pFrameInfo)
	{
		long frameType = pFrameInfo->nType;
		if (pBuf)
		{
			//std::cout << "HCSdkDecCallBackMend ! frameType = " << frameType << "nPort = "<<nPort<<std::endl;
			if (frameType == T_YV12)
			{
				int width = pFrameInfo->nWidth;
				int height = pFrameInfo->nHeight;

				cv::Mat sMat(height + height / 2, width, CV_8UC1, (char *)pBuf);
				if (-1 < num) {
					gCam_img_info[num].frame_num++;
					if (gCam_img_info[num].frame_num % 10 == 0) {
						gCam_img_info[num].last_img_mtx.lock();
                        cvtColor(sMat, gCam_img_info[num].last_img, CV_YUV2BGR_YV12);
						gCam_img_info[num].last_img_mtx.unlock();
#if 0
						//存本地
						char path[64] = {};
						sprintf_s(path, sizeof(path), "%d_%d.jpg", num, gCam_img_info[num].frame_num);
						cv::imwrite(path, gCam_img_info[num].last_img);
#endif
					}
				}
			}
		}
	}
	pBuf = nullptr;
	pFrameInfo = nullptr;
}
